from . import json as _json
from ..extensions import marshmallow as ma
from marshmallow import fields


class Success(ma.Schema):
    def jsonify(self, data, many=None, *args, **kwargs):
        rv = None
        if many is None:
            rv = super().jsonify(data, *args, **kwargs)
        else:

            rv = super().jsonify(data, many, *args, **kwargs)
        return rv
        from flask import request

        if request.method == 'POST':
            rv.code = 201
            return rv
        else:
            rv.code = 200
            return rv

    #
    # items = fields.Dict()
    # pagination = fields.Dict()

    class Meta:
        json_module = _json
        # fields = ('items',)
        dateformat = '%Y/%m/%d %H:%M:%S'


class ProductBase(Success):
    title = fields.Str()
    sub_title = fields.Str()
    id = fields.Str()
    type = fields.Str()
    status = fields.Str()
    cover = fields.Str()
    like_count = fields.Integer()
    click_count = fields.Integer()
    collection_count = fields.Integer()
    # content = fields.Function(
    #     lambda product, context: ProductContentSchema().dump(product.get_content(context.get('language', None)),
    #                                                          many=True).data)

    metadata = fields.Method('_write_metadata')

    def _write_metadata(self, data):
        metadata_map = {}
        for m in data.metadata:
            metadata_map[m.metadata_id] = {
                'screen_name': m.metadata.screen_name,
                'value_mode': m.metadata.value_mode,
                'value': m.value
            }
        return metadata_map


class ProductMetadataSchema(Success):
    metadata = fields.Method('_write_metadata')

    def _write_metadata(self, data):
        return {
            'id': data.metadata.id,
            'screen_name': data.metadata.screen_name,
            'value_mode': data.metadata.value_mode,
            'value': data.value,
            'extension': data.metadata.extension
        }


class CountrySchema(Success):
    id = fields.Str()
    screen_name = fields.Str()
    logo = fields.Str()


class MemberSchema(Success):
    id = fields.Str()
    screen_name = fields.Str()
    sales_rate = fields.Number()
    head_image = fields.Str()
    buyer_rate = fields.Number()
    deal_count = fields.Number()
    country = fields.Nested(CountrySchema)


class OfferSchema(Success):
    id = fields.Str()
    product = fields.Nested(ProductBase, only=['id', 'title', 'cover'])
    price = fields.Method(serialize='_tprice')
    member = fields.Nested(MemberSchema, dump_to='dealer', load_from='dealer')
    count = fields.Int()
    sales_count = fields.Int()
    status = fields.Str()

    # remaining = fields.Function(lambda x: int(x.count) - int(x.sales_count))

    def _tprice(self, stock):
        if 'currency' in self.context:
            currency = self.context.get('currency')
            return float(round((stock.price * currency.rate), 2))
        else:
            return float(round(stock.price, 2))


class CurrencySchema(Success):
    id = fields.Str()
    screen_name = fields.Str()
    logo = fields.Str()
    # rate = fields.Str()
    # type = fields.Str()
    prefix = fields.Str()
    suffix = fields.Str()


class RecommendStockSchema(Success):
    stock = fields.Nested(OfferSchema)
    additional = fields.Method('_serialize_additional')
    name = fields.Str()

    def _serialize_additional(self, data):

        currency = self.context.get('currency', None)

        if data and 'additional' in data:
            from decimal import Decimal
            for additional in data['additional']:
                if currency:
                    additional['amount'] = float(round(additional['amount'] * currency.rate, 2))
        return data.get('additional', [])


class ProductOfferResp(Success):
    currency = fields.Nested(CurrencySchema, exclude=['rate', 'type'])
    stock = fields.Nested(OfferSchema, many=True, exclude=['product'])
    recommend = services = fields.Nested(RecommendStockSchema)


class ProductCategorySchema(Success):
    id = fields.Str()


class PriceStatSchema(Success):
    minimum = fields.Number()
    maximum = fields.Number()
    average = fields.Number()


class ProductContentSchema(Success):
    language = fields.Str()
    summary = fields.Str()
    detail = fields.Str()


class ProductSchema(ProductBase):
    content = fields.Method("_write_content")
    category = fields.Nested(ProductCategorySchema)
    offer = fields.Method("_write_offer")

    def _write_offer(self, data):
        offer = data.offer
        if offer:
            price_stat_schema = PriceStatSchema()

            return price_stat_schema.dump(offer).data
        return {}

    def _write_content(self, data):
        language = self.context.get('language', None)
        _content = {}
        schema = ProductContentSchema()
        for content in data.get_content(language):
            _content[content.language] = schema.dump(content).data
        return _content


class ProductWithPrice(ProductBase):
    min_price = fields.Number()
    max_price = fields.Number()


class MoreProduct(Success):
    items = fields.Nested(ProductWithPrice, many=True)
    last_id = fields.Str()
    remaining = fields.Int()
    currency = fields.Nested(CurrencySchema, many=False)


class ServiceSchema(ma.Schema):
    id = fields.Str()
    fee = fields.Method(serialize='_serialize_fee')
    screen_name = fields.Str()
    short_name = fields.Str()
    mode = fields.Str()

    def _serialize_fee(self, service):

        if service.mode == 'fixed':
            if 'currency' in self.context:
                currency = self.context.get('currency')
                return float(round((service.fee * currency.rate), 2))
            else:
                return float(round(service.fee, 2))
        elif service.mode == 'rate':
            if 'price' in self.context:
                price = self.context.get('price')
                fee = price * service.fee
                if 'currency' in self.context:
                    currency = self.context.get('currency')
                    return float(round((fee * currency.rate), 2))
                else:
                    return float(round(fee, 2))


class ServiceWithCurrencyResp(ServiceSchema):
    # service = fields.Nested(ServiceSchema)
    currency = fields.Nested(CurrencySchema)


more_product = MoreProduct(many=False)
success_resp = Success(many=False)
currency_resp = CurrencySchema(many=False)

product_with_price_list_resp = ProductWithPrice(many=True)
